今天要來說明如何在Compose中進行基本的跳換頁面的動作功能。
說是跳轉頁面,但事實上偏向Java、Kotlin中的Fragment功能類似,需要一個觸發按鈕來運作。
這邊會先從簡易的跳轉頁面開始實作說明,後面還有進階一些的跳轉撰寫方法。
這邊依照以下步驟進行新增。
圖1. 到檔案資料夾點擊滑鼠右鍵->New->Compose->Empty Activity
圖2. 頁面,之後進行命名後點擊Finish即可成功建立。

Navigation 的 3 大主要部分是 NavController、 NavGraph 和  NavHost。
這是今天跳換頁面會用到的功能。
今天會以NavHost的startDestination、navController參數來建成一個極簡的跳轉功能,並會搭配NavGraphBuilder.composable來組成頁面跳轉。
NavHostController 對象,用於管理和控制導覽操作。 它負責追蹤當前的導航狀態以及執行導航操作,如 navigate、popBackStack 等。Modifier 對象,用於定義 NavHost 的修飾符。NavHost 中的對齊方式,例如 Alignment.Center、Alignment.TopStart 等等的排列參數。NavHost 所在的路由。 通常情況下,您不需要指定此參數,因為 NavHost 通常是根層級的,但在某些情況下,可以使用它來嵌套多個 NavHost。Lambda 函數,用於定義當導航到新目標時應用的進入動畫。Lambda 函數,用於定義當從當前目標導航到新目標時應用的退出動畫。Lambda 函數,用於定義當從後退堆疊中的目標導航回當前目標時應用的進入動畫。Lambda 函數,用於定義當從後退堆疊中的目標導航回當前目標時應用的退出動畫。Lambda 函數,用來建立導航圖。 在這裡,您可以使用 NavGraphBuilder 物件來定義導航目標和路由之間的關係,以及每個目標的內容。以上是所有的NavHost參數說明,今天只會使用到前面兩個參數來建立簡易的跳轉功能。
@Composable
@ComposableTarget
public fun NavHost(
    navController: NavHostController,
    startDestination: String,
    modifier: Modifier = COMPILED_CODE,
    contentAlignment: Alignment = COMPILED_CODE,
    route: String? = COMPILED_CODE,
    enterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition = COMPILED_CODE,
    exitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition = COMPILED_CODE,
    popEnterTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> EnterTransition = COMPILED_CODE,
    popExitTransition: AnimatedContentTransitionScope<NavBackStackEntry>.() -> ExitTransition = COMPILED_CODE,
    builder: NavGraphBuilder.() -> Unit
): Unit
這邊起始畫面為MainActivity,接著建立個跳轉頁面的方法及跳轉目的地。
NavHost(navController = navController,
        startDestination = "mainActivity") {
    composable("mainActivity") { GreetingBackground() }
    composable("homepage") { Background() }
    composable("searchActivity") { SearchBackground() }
    composable("profileActivity") { ProfileBackground() }
    composable("settingActivity") { SettingBackground() }
}
// 讓跳轉重複點擊只會有單次挑轉,不會有反覆恆跳的感覺出現,也就是當我們每次點擊時都會先跳回主畫面在進行跳轉,但當我們。
fun NavHostController.navigateSingleTopTo(route: String) =
    this.navigate(route) { launchSingleTop = true }
@Composable
private fun BottomNavigation(modifier: Modifier = Modifier, context:Context) {
    val navController = rememberNavController()
    val homeBool = remember {mutableStateOf(false)}
    val menuBool = remember {mutableStateOf(false)}
    val searchBool = remember {mutableStateOf(false)}
    val profileBool = remember {mutableStateOf(false)}
    val settingBool = remember {mutableStateOf(false)}
    
    NavHost(navController = navController,
            startDestination = "mainActivity") {
        composable("mainActivity") { GreetingBackground() }
        composable("homepage") { Background() }
        composable("searchActivity") { SearchBackground() }
        composable("profileActivity") { ProfileBackground() }
        composable("settingActivity") { SettingBackground() }
    }
    Row (modifier = Modifier.fillMaxHeight()){
        NavigationBar(
            //...省略
        ){
            // Menu
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = !menuBool.value,
                onClick = {
                    // 將其餘選項關閉,由於menu是反向所以false
                    false.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    Log.e(TAG, "SootheBottomNavigation: Home" )
                    // 利用建立的.navigateSingleTopTo來達到單次跳轉至指定頁面。
                    navController.navigateSingleTopTo("MainActivity")
                    Toast.makeText(context, "Home", Toast.LENGTH_SHORT).show()
                },
                // 其餘參數調整部分省略
            )
            
            // Home
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = homeBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    true.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    Log.e(TAG, "SootheBottomNavigation: Home" )
                    navController.navigateSingleTopTo("homepage")
                    Toast.makeText(context, "Home", Toast.LENGTH_SHORT).show()
                },
                // 其餘參數調整部分省略
            )
            
            // Search
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = searchBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    true.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    navController.navigateSingleTopTo("searchActivity")
                    Log.e(TAG, "SootheBottomNavigation: Search" )
                    Toast.makeText(context, "Search", Toast.LENGTH_SHORT).show()
                }
                // 其餘參數調整部分省略
            )
            
            // Profile
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = profileBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    true.also { profileBool.value = it }
                    false.also { settingBool.value = it }
                    navController.navigateSingleTopTo("profileActivity")
                    Log.e(TAG, "SootheBottomNavigation: Account" )
                    Toast.makeText(context, "Account", Toast.LENGTH_SHORT).show()
                }
                // 其餘參數調整部分省略
            )
            
            // Setting
            NavigationBarItem(
                // 判斷是否有選擇,因起始畫面為menu所以反向為true。
                selected = settingBool.value,
                onClick = {
                    true.also { menuBool.value = it }
                    false.also { homeBool.value = it }
                    false.also { searchBool.value = it }
                    false.also { profileBool.value = it }
                    true.also { settingBool.value = it }
                    navController.navigateSingleTopTo("settingActivity")
                    Log.e(TAG, "SootheBottomNavigation: Settings" )
                    Toast.makeText(context, "Setting", Toast.LENGTH_SHORT).show()
                }
                // 其餘參數調整部分省略
            )
        }
    }
}
以上是在主頁面的底部導覽條功能修改,接著就是撰寫其他跳轉後的頁面布置了,這邊就以一個去做程式碼展示,因為各自跳轉的需求不同,有不同的頁面配置。
@Composable
fun SettingsSelect() {
    val context = LocalContext.current
    Column (Modifier.fillMaxWidth()){
        Text(text = "設定",
            Modifier
                .padding(10.dp)
                .fillMaxWidth()
                .align(Alignment.CenterHorizontally),
            fontSize = MaterialTheme.typography.headlineLarge.fontSize,
            fontStyle = MaterialTheme.typography.headlineLarge.fontStyle,
            textAlign = MaterialTheme.typography.headlineLarge.textAlign,
            color = MaterialTheme.colorScheme.onBackground)
        ElevatedButton(onClick = {
            Toast.makeText(context, "SelfInfo Modify!", Toast.LENGTH_SHORT).show()
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.AccountCircle,
                contentDescription = null)
            Text(text = "個人資料修改")
        }
        ElevatedButton(onClick = {
            Toast.makeText(context, "Schedule", Toast.LENGTH_SHORT).show()
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.DateRange,
                contentDescription = null)
            Text(text = "行事曆")
        }
        ElevatedButton(onClick = {
            Toast.makeText(context, "password reset!", Toast.LENGTH_SHORT).show()
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.Lock,
                contentDescription = null)
            Text(text = "密碼重製")
        }
        ElevatedButton(onClick = {
            Toast.makeText(context, "Logout your account!", Toast.LENGTH_SHORT).show()
            Log.e(TAG, "SettingsSelect: Logout your account!" )
        },Modifier.fillMaxWidth()) {
            Icon(imageVector = Icons.Default.ExitToApp,
                contentDescription = null)
            Text(text = "登出")
        }
    }
}
@Composable
fun SettingBackground(){
    Box(modifier = Modifier
        .fillMaxSize()
        .background(MaterialTheme.colorScheme.background)) {
        Column (Modifier.padding(10.dp)){
            SettingsSelect()
        }
    }
}
這邊展示了五個頁面橫向跳轉,並包含一個跳轉過程的截圖。
以上是今天關於Navigation的跳轉功能實作與說明,也能看到因為改了點擊的布林變數的變換,所以底下的導覽條會根據目前所在的頁面一同更改selected參數的是否。